/*
 * Copyright (C) 2009 Kristopher T Babic
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of
 * the GNU General Public License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this program;
 * if not, see <http://www.gnu.org/licenses>.
 */

package edu.idp.client;

import edu.idp.client.anim.AnimationPath;
import edu.idp.client.anim.CirclePath;
import edu.idp.client.anim.LinePath;
import edu.idp.client.anim.SinePath;
import edu.idp.client.event.AnimationPathEvent;
import edu.idp.client.interfaces.AnimationPathEventListener;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.geom.Point2D;
import java.util.Vector;

/**
 *
 * @author Kristopher T Babic
 */
public class AnimationPathPanel extends JPanel implements ItemListener, ChangeListener {

    static public final int EVENT_CANCEL = 0;
    static public final int EVENT_SETPATH = 1;

    private AnimationPanel anim = null;
    private Vector animationPathEventListeners = null;
    private int pathType = -1;

    private Button cancelButton;
    private Button setPathButton;

    private Choice pathSelect = null;

    private BSlider speedSlider;
    private BDirection directionPointer;

    private BSlider slider_01 = null;
    private BSlider slider_02 = null;
    private BSlider slider_03 = null;

    private JLabel label_01 = null;
    private JLabel label_02 = null;
    private JLabel label_03 = null;

    public AnimationPathPanel() {
        //this.anim = ap;

        setLayout(null);
        setSize(400, 250);
        this.setBackground(new java.awt.Color(12632256));

        cancelButton = new Button("Cancel");
        cancelButton.setBackground(new java.awt.Color(12632256));
        cancelButton.setBounds(300, 165, 100, 30);
        this.add(cancelButton);

        setPathButton = new Button("Set Path");
        setPathButton.setBackground(new java.awt.Color(12632256));
        setPathButton.setBounds(20, 165, 100, 30);
        this.add(setPathButton);

        pathSelect = new Choice();
        pathSelect.add("Line");
        pathSelect.add("Ellipse");
//    pathSelect.add("Sphere");
        pathSelect.add("Sine");
//    pathSelect.add("Random");
        pathSelect.setBounds(20, 20, 100, 30);
        pathSelect.addItemListener(this);
        this.add(pathSelect);
        pathSelect.select("Line");

        SymAction sym = new SymAction();

        cancelButton.addActionListener(sym);
        setPathButton.addActionListener(sym);

        initLine();

    }

    protected void reset() {

        if (speedSlider != null) {
            this.remove(speedSlider);
            speedSlider = null;
        }

        if (directionPointer != null) {
            this.remove(directionPointer);
            directionPointer = null;
        }

        if (slider_01 != null) {
            this.remove(slider_01);
            slider_01 = null;
        }

        if (slider_02 != null) {
            this.remove(slider_02);
            slider_02 = null;
        }

        if (slider_03 != null) {
            this.remove(slider_03);
            slider_03 = null;
        }

        if (label_01 != null) {
            this.remove(label_01);
            label_01 = null;
        }
        if (label_02 != null) {
            this.remove(label_02);
            label_02 = null;
        }
        if (label_03 != null) {
            this.remove(label_03);
            label_03 = null;
        }

    }

    protected void initLine() {
        if (this.pathType == AnimationPath.LINE)
            return;

        this.pathType = AnimationPath.LINE;

        reset();
//    while(this.getComponentCount() != 3)
//      this.remove(3);

        label_01 = new JLabel("Path Direction:");
        label_01.setBounds(125, 5, 100, 20);
        add(label_01);

        directionPointer = new BDirection();
        directionPointer.setSize(100, 100);
        directionPointer.setBounds(250, 5, 100, 100);
        this.add(directionPointer);

        label_02 = new JLabel("Path Speed:");
        label_02.setBounds(125, 115, 75, 20);
        this.add(label_02);

        speedSlider = new BSlider(30);
        speedSlider.setSize(50, 30);
        speedSlider.setBounds(200, 120, 200, 40);
        speedSlider.addChangeListener(this);
        this.add(speedSlider);

        repaint();

    }

    protected void initEllipse() {
        if (this.pathType == AnimationPath.ELLIPSE)
            return;

        this.pathType = AnimationPath.ELLIPSE;

        reset();
//    while(this.getComponentCount() != 3)
//      this.remove(3);

        label_01 = new JLabel("X Radius:");
        label_02 = new JLabel("Y Radius:");
        label_03 = new JLabel("Delta Angle:");

        label_01.setBounds(125, 5, 70, 20);
        label_02.setBounds(125, 55, 70, 20);
        label_03.setBounds(125, 105, 70, 20);

        add(label_01);
        add(label_02);
        add(label_03);

        slider_01 = new BSlider(300);
        slider_01.setSize(50, 30);
        slider_01.setBounds(200, 10, 200, 40);
        slider_01.addChangeListener(this);
        this.add(slider_01);

        slider_02 = new BSlider(300);
        slider_02.setSize(50, 30);
        slider_02.setBounds(200, 60, 200, 40);
        slider_02.addChangeListener(this);
        this.add(slider_02);

        slider_03 = new BSlider(30);
        slider_03.setSize(50, 30);
        slider_03.setBounds(200, 110, 200, 40);
        slider_03.addChangeListener(this);
        this.add(slider_03);

/*
    x_radius = new TextField (4);
    x_radius.setBounds(200, 15, 50, 30);
    add(x_radius);

    y_radius = new TextField (4);
    y_radius.setBounds(200, 50, 50, 30);
    add(y_radius);

    angle = new TextField (4);
    angle.setBounds(200, 85, 50, 30);
    add(angle);
*/
        repaint();

    }

    protected void initSine() {
        if (this.pathType == AnimationPath.SINE)
            return;
        this.pathType = AnimationPath.SINE;

        reset();
//    while(this.getComponentCount() != 3)
//      this.remove(3);
        label_01 = new JLabel("Amplitude:");
        label_02 = new JLabel("Frequency:");
        label_03 = new JLabel("Delta Angle:");

        label_01.setBounds(125, 5, 70, 20);
        label_02.setBounds(125, 55, 70, 20);
        label_03.setBounds(125, 105, 70, 20);

        add(label_01);
        add(label_02);
        add(label_03);


        slider_01 = new BSlider(300);
        slider_01.setSize(50, 30);
        slider_01.setBounds(200, 10, 200, 40);
        slider_01.addChangeListener(this);
        this.add(slider_01);

        slider_02 = new BSlider(0.0, 4.0);
        slider_02.setSize(50, 30);
        slider_02.setBounds(200, 60, 200, 40);
        slider_02.addChangeListener(this);
        this.add(slider_02);

        slider_03 = new BSlider(10);
        slider_03.setSize(50, 30);
        slider_03.setBounds(200, 110, 200, 40);
        slider_03.addChangeListener(this);
        this.add(slider_03);

/*
    x_radius = new TextField (4);
    x_radius.setBounds(200, 15, 50, 30);
    add(x_radius);

    y_radius = new TextField (4);
    y_radius.setBounds(200, 50, 50, 30);
    add(y_radius);

    angle = new TextField (4);
    angle.setBounds(200, 85, 50, 30);
    add(angle);
 */
        repaint();

    }

    protected void initSphere() {
        if (this.pathType == AnimationPath.SPHERE)
            return;
        this.pathType = AnimationPath.SPHERE;

        reset();
//    while(this.getComponentCount() != 3)
//      this.remove(3);

        repaint();

    }

    protected void initRandom() {
        if (this.pathType == AnimationPath.RANDOM)
            return;
        this.pathType = AnimationPath.RANDOM;

        reset();
//    while(this.getComponentCount() != 3)
//      this.remove(3);

        repaint();

    }

    public void paint(Graphics g) {
        g.translate(0, 0);//this.getLocationOnScreen().x, this.getLocationOnScreen().y);//-22);
        super.paint(g);

//System.out.println(gjt.Util.getFrame(this).getComponentCount());
//for(int i = 0; i < getComponentCount()+1; i++)
//  System.out.println(this.getComponent(i));
//System.out.println("b: "+this.getBounds() );
//System.out.println("l: "+this.getLocale() );
//System.out.println("ls: "+this.getLocationOnScreen() );


    }

    /**
     * *****************************************
     * methods for adding and manipulating AnimationPathEvents
     * ******************************************
     */
    public synchronized void addAnimationPathEventListener(AnimationPathEventListener ael) {
        if (animationPathEventListeners == null)
            animationPathEventListeners = new Vector();
        animationPathEventListeners.addElement(ael);
    }

    public synchronized void removeAnimationPathListener(AnimationPathEventListener ael) {
        if (animationPathEventListeners != null && ael != null)
            animationPathEventListeners.removeElement(ael);
    }

    protected void fireEvent(AnimationPathEvent ape) {
        if (animationPathEventListeners == null)
            return;
        Vector targets;
        synchronized (this) {
            targets = (Vector) animationPathEventListeners.clone();
        }

        for (int i = 0; i < targets.size(); i++) {
            AnimationPathEventListener target = (AnimationPathEventListener) targets.elementAt(i);
            target.handleAnimationPathEvent(ape);
        }

    }

    /**
     * ********************************
     * implementation of ItemListener
     * *********************************
     */
    public void itemStateChanged(ItemEvent e) {
        java.lang.String event = (String) e.getItem();
        int select = 0;
        if (event.equalsIgnoreCase("line"))
            initLine();
        else if (event.equalsIgnoreCase("ellipse"))
            initEllipse();
        else if (event.equalsIgnoreCase("sine"))
            initSine();
        else if (event.equalsIgnoreCase("sphere"))
            initSphere();
        else if (event.equalsIgnoreCase("random"))
            initRandom();

    }

    /**
     * ************************************
     * implementation of ChangeListener
     * *************************************
     */
    public void stateChanged(ChangeEvent e) {
        Object o = e.getSource();
        if (o == speedSlider) {

            //System.out.println(bs.getValue()+" out of "+bs.getMaximum()+" : "+bs.getPercent()+"%");
        }
        else if (o == directionPointer) {

        }


    }

    public int getPathType() {
        return this.pathType;
    }

    public void setPathType(int type) {
        this.pathType = type;
    }

    /**
     * ********************************
     * inside action class
     * *********************************
     */

    class SymAction implements java.awt.event.ActionListener {

        public void actionPerformed(java.awt.event.ActionEvent event) {
            Object object = event.getSource();
            if (object == cancelButton)
                cancelButton_ActionPerformed(event);
            else if (object == setPathButton)
                setPathButton_ActionPerformed(event);
        }

        private void cancelButton_ActionPerformed(java.awt.event.ActionEvent event) {
            AnimationPathPanel.this.fireEvent((AnimationPathEvent) null);
            gjt.Util.getFrame(AnimationPathPanel.this).dispose();
        }

        private void setPathButton_ActionPerformed(java.awt.event.ActionEvent event) {
            int pType = AnimationPathPanel.this.getPathType();
            AnimationPath ap = null;
            if (pType == AnimationPath.LINE) {
                Point2D.Double direction = null;
                direction = AnimationPathPanel.this.directionPointer.getUnitVector();

                double len = AnimationPathPanel.this.speedSlider.getValue();
                double mult = Math.sqrt(Math.pow(len, 2.0) / (Math.pow(direction.x, 2.0) + Math.pow(direction.y, 2.0)));

                Point2D.Double test = new Point2D.Double((((double) direction.x) * mult), (((double) direction.y) * mult));
                java.awt.Point finalDirection = new java.awt.Point((int) (((double) direction.x) * mult), (int) (((double) direction.y) * mult));

//        ap = new LinePath(new java.awt.Point(0,0),AnimationPath.LINE);
//        ap.setLineVector(finalDirection);
                ap = new LinePath(new java.awt.Point(0, 0), finalDirection);
            }
            else if (pType == AnimationPath.ELLIPSE) {
/*
        if ( x_radius == null || y_radius == null || angle == null ) {
          javax.swing.JOptionPane.showMessageDialog(AnimationPathPanel.this, "Error creating path, please try again.", "Path Creation Error", javax.swing.JOptionPane.ERROR_MESSAGE);
          return;
        }
 */

                int x_rad = 0;
                int y_rad = 0;
                double ang = 0.0;
/*
        if (x_radius.getText().equals("")) {
           javax.swing.JOptionPane.showMessageDialog(AnimationPathPanel.this, "You must enter a x radius.", "Path Creation Error", javax.swing.JOptionPane.ERROR_MESSAGE);
          return;
        }
        else if (y_radius.getText().equals("")) {
          javax.swing.JOptionPane.showMessageDialog(AnimationPathPanel.this, "You must enter a y radius.", "Path Creation Error", javax.swing.JOptionPane.ERROR_MESSAGE);
          return;
        }

        try { x_rad = Integer.parseInt(x_radius.getText()); }
        catch (Exception e) {
          javax.swing.JOptionPane.showMessageDialog(AnimationPathPanel.this, "You entered an invalid x radius.", "Path Creation Error", javax.swing.JOptionPane.ERROR_MESSAGE);
          return;
        }

        try { y_rad = Integer.parseInt(y_radius.getText()); }
        catch (Exception e) {
          javax.swing.JOptionPane.showMessageDialog(AnimationPathPanel.this, "You entered an invalid y radius.", "Path Creation Error", javax.swing.JOptionPane.ERROR_MESSAGE);
          return;
        }

        try { ang = Double.parseDouble(angle.getText()); }
        catch (Exception e) {
          javax.swing.JOptionPane.showMessageDialog(AnimationPathPanel.this, "You entered an invalid angle.", "Path Creation Error", javax.swing.JOptionPane.ERROR_MESSAGE);
          return;
        }
 */
                x_rad = (int) slider_01.getValue();
                y_rad = (int) slider_02.getValue();
                ang = (int) slider_03.getValue();

                CirclePath cp = new CirclePath();
                cp.setRadius(x_rad, y_rad);
                cp.setDeltaAngle(ang);
                ap = cp;
            }
            else if (pType == AnimationPath.SINE) {
/*
        if ( x_radius == null || y_radius == null || angle == null ) {
          javax.swing.JOptionPane.showMessageDialog(AnimationPathPanel.this, "Error creating path, please try again.", "Path Creation Error", javax.swing.JOptionPane.ERROR_MESSAGE);
          return;
        }
 */
                double amp = 0;
                double freq = 0;
                double ang = 0.0;
/*
        if (x_radius.getText().equals("")) {
           javax.swing.JOptionPane.showMessageDialog(AnimationPathPanel.this, "You must enter a x radius.", "Path Creation Error", javax.swing.JOptionPane.ERROR_MESSAGE);
          return;
        }
        else if (y_radius.getText().equals("")) {
          javax.swing.JOptionPane.showMessageDialog(AnimationPathPanel.this, "You must enter a y radius.", "Path Creation Error", javax.swing.JOptionPane.ERROR_MESSAGE);
          return;
        }

        try { amp = Double.parseDouble(x_radius.getText()); }
        catch (Exception e) {
          javax.swing.JOptionPane.showMessageDialog(AnimationPathPanel.this, "You entered an invalid amplitude.", "Path Creation Error", javax.swing.JOptionPane.ERROR_MESSAGE);
          return;
        }

        try { freq = Double.parseDouble(y_radius.getText()); }
        catch (Exception e) {
          javax.swing.JOptionPane.showMessageDialog(AnimationPathPanel.this, "You entered an invalid frequency.", "Path Creation Error", javax.swing.JOptionPane.ERROR_MESSAGE);
          return;
        }

        try { ang = Double.parseDouble(angle.getText()); }
        catch (Exception e) {
          javax.swing.JOptionPane.showMessageDialog(AnimationPathPanel.this, "You entered an invalid angle.", "Path Creation Error", javax.swing.JOptionPane.ERROR_MESSAGE);
          return;
        }
 */

                amp = slider_01.getValue();
                freq = slider_02.getValue();
                ang = slider_03.getValue();

                SinePath sp = new SinePath();
                sp.setAmplitude(amp);
                sp.setFrequency(freq);
                sp.setDeltaAngle(ang);
                ap = sp;
            }

            AnimationPathPanel.this.fireEvent(new AnimationPathEvent(AnimationPathPanel.this, ap, AnimationPath.LINE));
            gjt.Util.getFrame(AnimationPathPanel.this).dispose();
        }
    }


}
